/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hmy.spi.annotation;


import com.hmy.spi.SPILoader;
import com.hmy.spi.Protocol;

import java.lang.annotation.*;

/**
 * Provide helpful information for {@link SPILoader} to inject dependency extension instance.
 * 1. 在类上加上@Adaptive注解的类，是最为明确的创建对应类型Adaptive类。所以他优先级最高。
 * 2. @SPI注解中的value是默认值，如果通过URL获取不到关于取哪个类作为Adaptive类的话，就使用这个默认值，当然如果URL中可以获取到，就用URL中的。
 * 3. 可以再方法上增加@Adaptive注解，注解中的value与链接中的参数的key一致，链接中的key对应的value就是spi中的name,获取相应的实现类。
 * <p>
 * 在 Dubbo 中，@Adaptive 注解是用来标记 Dubbo 扩展点自适应类的注解。Dubbo 的扩展点可以有多种实现方式，而每次调用需要使用其中一种实现方式。
 * 在这种情况下，Dubbo 使用 @Adaptive 注解来动态生成该扩展点的自适应类，
 * <span style="color:red;font-size:12px">用于根据不同的参数值选择合适的实现方式，以便与各种不同环境和场景协同工作。</span>
 * <p>
 * 使用 @Adaptive 注解时，需要注意以下几点：
 * 1. @Adaptive 注解只能用于接口方法或类上。
 * 2. 被 @Adaptive 注解标记的接口方法或类必须具有至少一个方法参数，并且该参数必须是一个字符串类型的键值对，用于指定当前要使用的 Dubbo 扩展点实现的名称。
 * 3. 由于 Dubbo 的自适应类需要通过反射机制生成，所以被 @Adaptive 注解标记的接口方法或类必须有一个无参构造函数。
 * <p>
 * 需要注意的是，@Adaptive 注解只能在扩展点接口上标注一次。如果有多个实现类需要使用 @Adaptive 注解，则应该定义一个适配器类，
 * 将 @Adaptive 注解标注在适配器类上，并在适配器类中根据参数值动态选择合适的实现类来执行方法调用。
 * @see SPILoader
 * @see Protocol
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
    /**
     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
     * in the URL, and the parameter names are given by this method.
     * <p>
     * If the specified parameters are not found from {@link Protocol}, then the default extension will be used for
     * dependency injection (specified in its interface's {@link SPI}).
     * <p>
     * For examples, given <code>String[] {"key1", "key2"}</code>:
     * <ol>
     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>
     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>
     * <li>use default extension if 'key2' doesn't appear either</li>
     * <li>otherwise, throw {@link IllegalStateException}</li>
     * </ol>
     * If default extension's name is not give on interface's {@link SPI}, then a name is generated from interface's
     * class name with the rule: divide classname from capital char into several parts, and separate the parts with
     * dot '.', for example: for {@code org.apache.dubbo.xxx.YyyInvokerWrapper}, its default name is
     * <code>String[] {"yyy.invoker.wrapper"}</code>. This name will be used to search for parameter from URL.
     *
     * @return parameter key names in URL
     */
    String[] value() default {};

}